/**
 * 
 */
package edu.umd.clip.lm.playground;

import java.io.IOException;
import java.net.*;
import java.util.Timer;

import edu.berkeley.nlp.util.*;
import edu.umd.clip.lm.factors.FactorTupleDescription;
import edu.umd.clip.lm.model.*;
import edu.umd.clip.lm.storage.AbstractProbTreeStorage;
import edu.umd.clip.lm.storage.AsyncConsumer;
import edu.umd.clip.lm.storage.remote.*;
import edu.umd.clip.lm.storage.remote.ServerStorageConnection.Task;

/**
 * @author Denis Filimonov <den@cs.umd.edu>
 *
 */
public class DummyStorageServer {
	public static class Options {
        @Option(name = "-config", usage = "XML config file")
		public String config;
        @Option(name = "-jobs", usage = "number of concurrent jobs (default: 1)")
        public int jobs = 1;
        @Option(name = "-forest", required = false, usage = "top level LM (default: " + LanguageModel.PRIMARY_LM_ID + ")")
		public String lm = LanguageModel.PRIMARY_LM_ID;
        @Option(name = "-port", required = false, usage = "TCP port to listen at (default: 2332)")
        public int port = 2332;
	}

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
        OptionParser optParser = new OptionParser(Options.class);
        final Options opts = (Options) optParser.parse(args, true);

        SocketAddress address = new InetSocketAddress(opts.port);
		final ServerStorageConnection connection = new ServerStorageConnection(address);

		Experiment.initialize(opts.config);
		final Experiment experiment = Experiment.getInstance();

		experiment.buildPrefixes();
		experiment.buildWordPrefixes();

		DecoderCompactProbTree emptyTree = DecoderCompactProbTree.constructEmptyTree(Experiment.getInstance().getHFT().getTree());
		DecoderCompactProbTree.setEmptyTree(emptyTree);

		if (emptyTree == null) {
			System.err.println("failed to  DecoderCompactProbTree.constructEmptyTree");
			System.exit(1);
		}
		AbstractProbTreeStorage storage = new DummyProbTreeStorage();
		//storage = new CachedProbTreeStorage(storage, 1000, 2000);
		
		final ServerStorageResponder responder = new ServerStorageResponder(storage, connection);
		
		Timer timer = new Timer(true);
		timer.scheduleAtFixedRate(new ServerStorageConnection.ServerMonitor(connection), 0, ServerStorageConnection.ServerMonitor.INTERVAL);

		for(int i=0; i<opts.jobs; ++i) {
			new Worker(connection, responder).start();
		}
		try {
			while(true) {
				Thread.sleep(1000000);
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}

	private static class DummyProbTreeStorage extends AbstractProbTreeStorage {
		
		/* (non-Javadoc)
		 * @see edu.umd.clip.lm.storage.AbstractProbTreeStorage#getProbTree(edu.umd.clip.lm.storage.AbstractProbTreeStorage.Key)
		 */
		DummyProbTreeStorage() {
			super();
		}

		@Override
		public OnDiskCompactProbTree getProbTree(Key key) {
			FactorTupleDescription desc = Experiment.getInstance().getTupleDescription(); 
			long tuple = desc.createStartTuple();
			tuple &= desc.getOvertFactorsMask();
			if (DecoderCompactProbTree.getEmptyTree() == null) {
				System.err.println("null emptyTree");
				System.exit(2);
			}
			OnDiskCompactProbTree probTree = new OnDiskCompactProbTree(1);
			//probTree.setTree(DecoderCompactProbTree.getEmptyTree());
			return probTree;
		}

		/* (non-Javadoc)
		 * @see edu.umd.clip.lm.storage.AbstractProbTreeStorage#getStats()
		 */
		@Override
		public String getStats() {
			return null;
		}

		/* (non-Javadoc)
		 * @see edu.umd.clip.lm.storage.AbstractProbTreeStorage#requestProbTree(edu.umd.clip.lm.storage.AbstractProbTreeStorage.Key)
		 */
		@Override
		protected void requestProbTree(Key key) {
		}

		/* (non-Javadoc)
		 * @see edu.umd.clip.lm.storage.AbstractProbTreeStorage#setProbTree(edu.umd.clip.lm.storage.AbstractProbTreeStorage.Key, edu.umd.clip.lm.model.ProbTree)
		 */
		@Override
		public void setProbTree(Key key, OnDiskCompactProbTree probTree) {
		}

		/* (non-Javadoc)
		 * @see edu.umd.clip.lm.storage.AsyncProducer#request(java.lang.Object, edu.umd.clip.lm.storage.AsyncConsumer)
		 */
		@Override
		public void request(Key key, AsyncConsumer<Key, OnDiskCompactProbTree> callback) {
			// TODO Auto-generated method stub
			
		}

		/* (non-Javadoc)
		 * @see edu.umd.clip.lm.storage.AbstractProbTreeStorage#closeAll()
		 */
		@Override
		public void closeAll() {
			// TODO Auto-generated method stub
			
		}
		
	}
	private static class Worker extends Thread {
		ServerStorageConnection connection;
		ServerStorageResponder responder;
		
		public Worker(ServerStorageConnection connection, ServerStorageResponder responder) {
			this.connection = connection;
			this.responder = responder;
		}

		public void run() {
			while(!isInterrupted()) {
				Task task = connection.getNextTask();
				
				responder.process(task);
			}
		}
	}

}
